package packutil.throttle;

import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;

import packutil.exception.InvalidArgumentException;

public class ThrottleDefaultImpl implements IThrottle {

	public static final long DEFAULT_SLEEP_TIME_MILLIS = 10;

	protected long sleepTimeMillis = DEFAULT_SLEEP_TIME_MILLIS;

	protected ThrottleRatePeriod ratePeriod;

	protected int rate;

	protected Queue<Long> touchHistory = new LinkedList<Long>();

	public ThrottleDefaultImpl(int rate, ThrottleRatePeriod ratePer) {
		resetRate(rate, ratePer);
	}

	public void resetRate(int rate, ThrottleRatePeriod ratePeriod) {

		if (rate <= 0) {
			throw new InvalidArgumentException("Throttle rate must be > 0");
		}

		if (ratePeriod == null) {
			throw new InvalidArgumentException("Rate period is null");
		}

		this.rate = rate;
		this.ratePeriod = ratePeriod;
	}

	public void setSleepTime(long sleepTimeMillis) {
		this.sleepTimeMillis = sleepTimeMillis;
	}

	public void touch() {

		long time = new Date().getTime();

		final int millisPerSecond = 1000;
		final int millisPerMinute = 1000 * 60;
		final int millisPerHour = 60000 * 60;

		while (touchHistory.size() >= rate) {

			int diff = (int) (time - touchHistory.peek());
			if (ThrottleRatePeriod.Second.equals(ratePeriod)) {
				diff /= millisPerSecond;
			} else if (ThrottleRatePeriod.Minute.equals(ratePeriod)) {
				diff /= millisPerMinute;
			} else if (ThrottleRatePeriod.Hour.equals(ratePeriod)) {
				diff /= millisPerHour;
			}

			if (diff > 0) {
				touchHistory.poll();
			}

			try {
				Thread.sleep(sleepTimeMillis);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}

			time = new Date().getTime();
		}

		touchHistory.add(time);
	}
}